﻿package 
{	
	import org.flintparticles.twoD.renderers.DisplayObjectRenderer;
	import flash.text.TextFormat;
	import flash.text.TextField;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import org.flintparticles.common.counters.Steady;
	import org.flintparticles.common.initializers.ImageClass;
	import org.flintparticles.twoD.actions.DeathZone;
	import org.flintparticles.twoD.actions.MinimumDistance;
	import org.flintparticles.twoD.actions.Move;
	import org.flintparticles.twoD.actions.RotateToDirection;
	import org.flintparticles.twoD.emitters.Emitter2D;
	import org.flintparticles.twoD.initializers.Position;
	import org.flintparticles.twoD.renderers.BitmapRenderer;
	import org.flintparticles.twoD.zones.LineZone;
	import org.flintparticles.twoD.zones.RectangleZone;
	import silin.geom.FitLine;
	import silin.geom.Path;
	import silin.geom.PathPoint;
	import waylines.waypoints.ActionResistance;
	import waylines.waypoints.FollowWaylines;
	import waylines.waypoints.Wayline;

	public class MainWailines_1 extends Sprite
	{
		// массив с узлами пути
		protected var _waylines:Array;
		protected var emitterWaylines:Emitter2D;
		
		public function MainWailines_1()
		{
			if(stage != null)
			{
				setup();
			}
			else
			{
				addEventListener(Event.ADDED_TO_STAGE, setup);
			}
		}
		protected function setup(e:Event=null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, setup);
			
			drawBackround();
			
			setupWaylines();
			drawWaylines();
			
			setupEmitter();
			
			addChild(new FPSCounter());
			// да, не самая рекомендуемая конструкция - но это чтоб не захламлять основной "презентационный" код
			addEventListener(Event.ENTER_FRAME, function(e:Event):void
			{
				var textField:TextField = getChildByName("textfield") as TextField;
				if(textField == null)
				{
					textField = addChild(new TextField()) as TextField;
					textField.name = "textfield";
					textField.border = true;
					textField.defaultTextFormat = new TextFormat("_sans", 12, 0xff0000);
					textField.width = 50;
					textField.height = 22;
					textField.y = 22;
				}
				
				textField.text = String(emitterWaylines.particles.length);
				
			});
		}
		protected function setupWaylines():void
		{
			_waylines = [];
			
			var w:Number = stage.stageWidth;
			var h:Number = stage.stageHeight;
			/*
			 * 1. это я на глаз накидал координаты, просто доли умножая на ширину и высоту экрана
			 * 2. первую и последнюю точку расположил за пределами экрана, чтоб частицы появлялись из-за края экрана, а не из пустоты 
			 */  
			//var points:Array = [new Point(-9,h*.6), new Point(w*.3,h*.3), new Point(w*.5,h*.25), new Point(w*.6,h*.45), new Point(w*.7,h*.7), new Point(w*.8, h*.75), new Point(w*.9, h*.6), new Point(w*1.3, h*.5)];
			var points:Array = [new Point(-9,h*.4), new Point(w*.3,h*.4), new Point(w*.5,h*.1), new Point(w*.8,h*.1), new Point(w*.8,h*.9), new Point(w*.5, h*.9), new Point(w*.3, h*.8), new Point(-40, h*.8)];
			/*
			 * проблемы:
			 * 1. экземпляры Wayline должны быть выставлены перпендикулярно к касательной пути
			 * 2. количества первоначальных точек маловато для обеспечения плавности пути
			 * 3. лень вручную выставлять все необходимые параметры
			 * решение:
			 * взять нужный кусочек из полезнейшей библиотеки http://silin.su/#AS3, где
			 * 1. FitLine - класс, который "сглаживает" ломаные кривые
			 * 2. Path - класс, сохраняющий последовательность кривых Безье, которыми можно оперировать, как единым целым. Например - найти точку на пути.
			 * 3. "нарезать" получившийся сглаженный путь на нужное число точек
			 */
			var fitline:FitLine = new FitLine(points);
			var path:Path = new Path(fitline.fitPoints);
			/*
			 * ВАЖНО! - величине шага желательно быть больше скорости движния частицы - это ради упрощения расчетов. 
			 * Иначе, частица на скорости может "проскочить" следующую точку на пути, и "захочет" вернуться, или не впишется в резкий поворот. 
			 * В общем - будет выглядеть так, будто частица слетает с рельсов, или круги наматывает... Можете поэкспериментировать
			 */ 
			var step:Number = path.length / 40;
			/*
			 * сила притяжения точки на пути - помните, система частиц работает "на классической механике"?
			 * т.е. внутри системы частиц, частицу последовательно ускоряет к следующему узлу пути - как в адронном коллайдере
			 */
			var strength:Number = 100;
			// расставляем ноды на местности
			for(var i:int=0; i<path.length; i+=step)
			{
				// можно поиграться с рандомными размерами узлов на пути
				var segmentLength:int = 60;//*Math.random()+10;
				var pathpoint:PathPoint = path.getPathPoint(i);
				var wayline:Wayline = new Wayline(pathpoint.x, pathpoint.y, segmentLength, pathpoint.rotation-Math.PI/2, strength);
				_waylines.push(wayline);
			}
		}
		/*
		 * настраиваем эмиттер
		 */
		protected function setupEmitter():void
		{
			// --- создаем экземпляр класса и задаем параметры, которые которые будут применяться к частицам при их генерации -------------
			var emitter:Emitter2D = new Emitter2D();
			// это счетчик - генерирует определенное количество частиц в секунду
				emitter.counter = new Steady(60);
			// берем начало пути
				var wayline:Wayline = _waylines[0];
			// позиционируем зону генерации эмиттера LineZone таким образом, чтоб она совпадала с линией "внутри" Wayline 			
				emitter.addInitializer( new Position( new LineZone( new Point(wayline.x - wayline.radius*Math.cos(wayline.rotation), wayline.y - wayline.radius*Math.sin(wayline.rotation)), new Point(wayline.x + wayline.radius*Math.cos(wayline.rotation), wayline.y + wayline.radius*Math.sin(wayline.rotation)) ) ) );
			// сообщаем, какую картинку использовать рендеру при отрисовке частицы
				//emitter.addInitializer( new ImageClass( ArrowBitmap, [4] ) );
				emitter.addInitializer( new ImageClass( Arrow, [4] ) );
				
			// --- добавляем actions, которые в совокупности будут определять поведение частиц ---------------------------------------------
			// определяем зону вне которой частицы будут автоматически(!) уничтожаться. Т.е. области организации движения составляют своеобразную матрёшку
			// 1. снаружи (больше всех) - мёртвая зона - вне прямоугольника частицы автоматически уничтожаются
			// 2. посредине - узлы маршрута частиц (вне экрана устройства концы, при этом внутри "прямоугольника жизни")
			// 3. внутри матрёшки - экран устройства - с одной стороны частицы входят, с другой - выходят
			// на самом деле этот action можно не добавлять, потому что уничтожение частиц в конце пути осуществляет "главный" action FollowWaylines 
				emitter.addAction( new DeathZone( new RectangleZone( -30, -30, stage.stageWidth+60, stage.stageHeight + 60 ), true ) );
			// new Move() - дает возможность обновлять позицию частицы каждый фрейм. Т.е. - чтоб частица двигалась, к эмиттеру надо прицепить этот action
				emitter.addAction( new Move() );
			// это, чтоб персонажи были повернуты по направлению к движению 
				emitter.addAction( new RotateToDirection() );
			// определяет МИНИМАЛЬНУЮ дистанцию между частицами
				emitter.addAction( new MinimumDistance( 7, 600 ) );			
			// пришлось написать специальный action для ограничения скорости (есть и "родной" SpeedLimit, но он меня не устраивает - об этом в следующей статье расскажу)
				emitter.addAction( new ActionResistance(.4));
			// наш "доморощенный" action, который непосредственно и контролирует движение частицы по заданному маршруту
				emitter.addAction( new FollowWaylines(_waylines) );
		   	
		   	// создаем рендерер
		   	//var	renderer:BitmapRenderer = new BitmapRenderer(new Rectangle(0, 0, stage.stageWidth, stage.stageHeight));
		   	var	renderer:DisplayObjectRenderer = new DisplayObjectRenderer();
		   	// цепляем его на сцену
		   		addChild( renderer );
		   	// передаем в качестве параметра настроенный эмиттер
		   		renderer.addEmitter( emitter );
			// командуем старт
				emitterWaylines = emitter;			
				emitterWaylines.start();
		}
		/*
		 * рисуем фон		 
		 */
		protected function drawBackround():void
		{
			graphics.beginFill(0x999999);
			graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			graphics.endFill();
		}
		/*
		 * визуализируем узлы пути 		 
		 */
		protected function drawWaylines():void
		{
			var s:Sprite = this;
				
			
			for(var i:int=0; i<_waylines.length; i++)
			{
				var w:Wayline = _waylines[i];
				
				s.graphics.lineStyle(1,0xff0000, .2);
				s.graphics.beginFill(0x990000, .2);
				s.graphics.drawCircle(w.x, w.y, w.radius);
				s.graphics.endFill();
				
				/*s.graphics.lineStyle(1,0xff0000, .2);
				s.graphics.beginFill(0xff0000,.5);
				s.graphics.drawCircle(w.x, w.y, 1);
				s.graphics.endFill();*/
				
				//s.graphics.lineStyle(3,0xffffff);
				s.graphics.lineStyle(1,0xff0000);
				s.graphics.moveTo(w.x, w.y);
				s.graphics.lineTo(w.line.end.x, w.line.end.y);
			}
			
			s.cacheAsBitmap = true;
		}
	}
}
